package cn.zzz.gen;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Service
public class GenService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public void gen() throws Exception {
        List<String> tableNames = jdbcTemplate.queryForList("show tables;", String.class);
        for (int i = 0; i < tableNames.size(); i++) {
            String tableName = tableNames.get(i).toLowerCase();
            boolean match = Pattern.matches(GenConfig.tableRegex, tableName);
            if (match) {
                logger.info("----------------------");
                logger.info("开始生成相关信息" + tableName);
                genTable(tableName);
            }
        }
        if (GenConfig.isGenerateBaseService) {
            genBaseService(tableNames);
        }
    }


    //
    private void genTable(String tableName) throws Exception {
        List<Column> columns = jdbcTemplate.query("desc " + tableName + " ;", new BeanPropertyRowMapper<Column>(Column.class));
        Table table = new Table(tableName, columns);
        if (GenConfig.isGenerateEntity) {
            genEntity(table);
        }
        if (GenConfig.isGenerateEntityTbl) {
            genEntityTbl(table);
        }
        if (GenConfig.isGenerateDao) {
            genDao(table);
        }
        if (GenConfig.isGenerateDao2) {
            genDao2(table);
        }

        if (GenConfig.isGenerateService) {
            if (!GenConfig.serviceOnlyImpl) {
                genService(table);
            }
            genServiceImpl(table);
        }
        if (GenConfig.isGenerateTestService) {
            genServiceTest(table);
        }
    }


    private void genEntity(Table table) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.entityPackage() + ";");
        lines.add("");
        lines.add("import java.io.Serializable;");
        lines.add("import " + table.entityTblPackage() + "." + table.entityTblClassName() + ";");
        lines.add("import lombok.*;");
        lines.add("import javax.persistence.*;");
        lines.add("");
        lines.add("@Entity");
        lines.add("@Table(name = \"" + table.getName() + "\")");
        lines.add("@Getter");
        lines.add("@Setter");
        lines.add("public class " + table.entityClassName() + " extends " + table.entityTblClassName() + " implements Serializable {");
        lines.add("    private static final long serialVersionUID = 1L;");
        lines.add("");
        for (Column col : table.getColumns()) {
            if (col.isFK()) {
                lines.add("    @Transient");
                lines.add("    public " + ("Integer") + " " + col.genGetter() + "() {");
                lines.add("        return " + col.genFKObjGetter() + "() == null ? null : " + col.genFKObjGetter() + "()." + col.genGetter() + "();");
                lines.add("    }");
                lines.add("");
            }
        }
        for (Column col : table.getColumns()) {
            if(Byte.class.equals(col.javaType())||Short.class.equals(col.javaType())){
                lines.add("    @Transient");
                lines.add("    public " + ("String") + " " + col.genGetter() + "Str() {");
                lines.add("        return MessageUtils.getMessageDefault(\"" + table.entityClassName() + "." + col.getField() + ".\" + " + col.genGetter() + "());");
                lines.add("    }");
                lines.add("");
            }
        }
        for (Column col : table.getColumns()) {
            if ("picUrl".equals(col.getField())) {
                lines.add("    @Transient");
                lines.add("    public String getPicUrlAll() {");
                lines.add("        return OssUrlUtils.appendHttpIf(getPicUrl());");
                lines.add("    }");
                lines.add("");
            }
        }
        lines.add("}");
        FileUtils.writeLines(new File(table.entityFile()), "utf-8", lines, "\n");
    }

    private void genEntityTbl(Table table) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.entityTblPackage() + ";");
        lines.add("");
        lines.add("import java.io.Serializable;");
        lines.add("import lombok.*;");
        lines.add("import javax.persistence.*;");
        for (Class<?> clazz : table.importClazzes()) {
            lines.add("import " + clazz.getTypeName() + ";");
        }
        lines.add("");
        lines.add("@MappedSuperclass");
        lines.add("@Getter");
        lines.add("@Setter");
        lines.add("public class " + table.entityTblClassName() + " implements Serializable {");
        lines.add("    private static final long serialVersionUID = 1L;");
        lines.add("");
        //filed
        for (Column col : table.getColumns()) {
            if (col.isFK()) {
                lines.add("    @ManyToOne(fetch = FetchType.LAZY)");
                lines.add("    @JoinColumn(name = \"" + col.getField() + "\")");
                lines.add("    private " + col.genFKObjType() + " " + col.genFKObj() + ";");
            } else {
                if (col.isPK()) {
                    lines.add("    @Id");
                    lines.add("    @GeneratedValue(strategy = GenerationType.IDENTITY)");
                }
                if (col.isCreateTime()) {
                    lines.add("    @Column(updatable = false)");
                }
                if (col.isVersion()) {
                    lines.add("    @Version");
                }
                lines.add("    private " + col.javaType().getSimpleName() + " " + col.getField() + ";");
            }
        }
        lines.add("");
        lines.add("}");
        FileUtils.writeLines(new File(table.entityTblFile()), "utf-8", lines, "\n");

    }

    private void genDao(Table table) throws Exception{
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.daoPackage() + ";");
        lines.add("import "+table.entityClassNameAll()+";");
        lines.add("import org.springframework.data.jpa.repository.JpaRepository;");
        lines.add("import org.springframework.data.jpa.repository.JpaSpecificationExecutor;");

        lines.add("public interface "+table.daoClassName()+" extends JpaRepository<"+table.entityClassName()+", Integer>, JpaSpecificationExecutor<"+table.entityClassName()+"> {");
        lines.add("}");

        FileUtils.writeLines(new File(table.daoFile()), "utf-8", lines, "\n");
    }

    private void genDao2(Table table)throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.dao2Package() + ";");
        lines.add("import org.springframework.stereotype.Repository;");
        lines.add("import cn.zzz.zsf.common.base.ZsfBaseDao;");
        lines.add("import cn.zzz.zsf.common.base.BasePagination;");
        lines.add("");
        lines.add("@Repository");
        lines.add("public class "+table.dao2ClassName()+" extends ZsfBaseDao<BasePagination> {");
        lines.add("}");
        FileUtils.writeLines(new File(table.dao2File()), "utf-8", lines, "\n");
    }

    private void genService(Table table) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.servicePackage() + ";");
        lines.add("");
        lines.add("import cn.zzz.zsf.common.base.BasePagination;");
        lines.add("import " + GenConfig.serviceBasePackage + "." + GenConfig.ibaseServiceName + ";");
        lines.add("");
        lines.add("public interface " + table.serviceClassName() + " extends "+ GenConfig.ibaseServiceName+"<BasePagination> {");
        lines.add("");
        lines.add("}");
        FileUtils.writeLines(new File(table.serviceFile()), "utf-8", lines, "\n");

    }

    private void genServiceImpl(Table table) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.serviceImplPackage() + ";");
        lines.add("");
        lines.add("import lombok.extern.slf4j.Slf4j;");
        lines.add("import org.springframework.stereotype.Service;");
        lines.add("import org.springframework.beans.factory.annotation.Autowired;");
        lines.add("import org.springframework.context.annotation.Lazy;");
        lines.add("import " + GenConfig.serviceBasePackage + "." + GenConfig.baseServiceName + ";");
        if (!GenConfig.serviceOnlyImpl) {
            lines.add("import " + table.serviceClassNameAll() + ";");
        }
        lines.add("import cn.zzz.zsf.common.base.BasePagination;");
        lines.add("");
        lines.add("");
        lines.add("@Service");
        lines.add("@Slf4j");
        lines.add("public class " + table.serviceImplClassName() + " extends " + GenConfig.baseServiceName + "<BasePagination>" + (GenConfig.serviceOnlyImpl ? "" : (" implements " + table.serviceClassName())) + " {");
        lines.add("    @Autowired @Lazy");
        lines.add("    private "+ table.serviceClassName() +" service;");
        lines.add("}");
        FileUtils.writeLines(new File(table.serviceImplFile()), "utf-8", lines, "\n");

    }

    private void genServiceTest(Table table) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + table.servicePackage() + ";");
        lines.add("");
        lines.add("import org.springframework.beans.factory.annotation.Autowired;");
        lines.add("import " + GenConfig.serviceBasePackage + ".BaseTest;");
        lines.add("import " + table.serviceClassNameAll() + ";");
        lines.add("");
        lines.add("public class " + table.serviceClassName() + "Test extends BaseTest {");
        lines.add("    @Autowired");
        lines.add("    private " + table.serviceClassName() + " service;");
        lines.add("");
        lines.add("}");
        String testServiceFile = GenConfig.serviceProjectPath + "/src/test/java/" + table.servicePackage().replaceAll("\\.", "/") + "/" + table.serviceClassName() + "Test.java";
        ;
        FileUtils.writeLines(new File(testServiceFile), "utf-8", lines, "\n");
    }

    private void genBaseService(List<String> tableNames) throws Exception {
        List<String> lines = new ArrayList<>();
        lines.add("package " + GenConfig.serviceBasePackage + ";");
        lines.add("");
        lines.add("import cn.zzz.zsf.common.base.BasePagination;");
        lines.add("import cn.zzz.zsf.common.base.ZsfServiceImpl;");
        lines.add("import org.springframework.beans.factory.annotation.Autowired;");
        lines.add("");
        lines.add("public class " + GenConfig.baseServiceName + " <T extends BasePagination> extends ZsfServiceImpl<T> {");
        lines.add("");
        for (String tableName : tableNames) {
            Table table = new Table(tableName, null);
			lines.add("    @Autowired");
			lines.add("    protected "+table.daoClassNameAll()+" "+CamelUtils.firstChar2Lower(table.daoClassName())+";");
            lines.add("    @Autowired");
            lines.add("    protected "+table.dao2ClassNameAll()+" "+CamelUtils.firstChar2Lower(table.dao2ClassName())+";");
        }
        lines.add("");
        lines.add("}");
        String baseServiceFile = GenConfig.serviceProjectPath + "/src/main/java/" + GenConfig.serviceBasePackage.replaceAll("\\.", "/") + "/" + GenConfig.baseServiceName + ".java";
        FileUtils.writeLines(new File(baseServiceFile), "utf-8", lines, "\n");
        //
        List<String> lines2 = new ArrayList<>();
        lines2.add("package " + GenConfig.serviceBasePackage + ";");
        lines2.add("import cn.zzz.zsf.common.base.BasePagination;");
        lines2.add("import cn.zzz.zsf.common.base.ZsfService;");
        lines2.add("public interface "+ GenConfig.ibaseServiceName+"<T extends BasePagination> extends ZsfService<T> {");
        lines2.add("}");
        String ibaseServiceFile = GenConfig.serviceProjectPath + "/src/main/java/" + GenConfig.serviceBasePackage.replaceAll("\\.", "/") + "/" + GenConfig.ibaseServiceName + ".java";
        FileUtils.writeLines(new File(ibaseServiceFile), "utf-8", lines2, "\n");


    }
}
